package aor2.cpu.blockinterface;

import aor2.components.FlipFlopD;
import aor2.components.FlipFlopException;
import aor2.components.FlipFlopRS;
import aor2.components.Restorable;
import aor2.components.Signal;
import aor2.cpu.blockcontrol.ControlSignalSet;
import aor2.systembus.SystemBus;

public class BusOvertake implements Restorable {

	private boolean clkFstPhase;
	private FlipFlopRS br, busy;

	public FlipFlopRS getBr() {
		return br;
	}

	public FlipFlopRS getBusy() {
		return busy;
	}

	public FlipFlopD getStart() {
		return start;
	}

	private FlipFlopD start;
	Signal enFFC;
	private Signal komb1, komb2, brqstart, bgr, setbusy, read, write;
	Signal enrw, brs;
	private static BusOvertake singleton = null;
	private Arbitrator arb = Arbitrator.getInstance();
	private SystemBus sysbus = SystemBus.getInstance();

	// private SynchronizationBlock synblock =
	// SynchronizationBlock.getInstance();

	public Signal getKomb1() {
		return komb1;
	}

	public Signal getBrqstart() {
		return brqstart;
	}

	public Signal getBgr() {
		return bgr;
	}

	public Signal getSetbusy() {
		return setbusy;
	}

	public Signal getEnrw() {
		return enrw;
	}

	public Signal getBrs() {
		return brs;
	}

	public static BusOvertake getInstance() {
		if (null == singleton) {
			singleton = new BusOvertake();
		}
		return singleton;
	}

	private BusOvertake() {
		ControlSignalSet css = ControlSignalSet.getInstance();

		this.komb1 = new Signal(false);
		this.komb2 = new Signal(false);
		this.brqstart = new Signal(false); // this.brqstart.addDestinationElementIO(br);
		this.bgr = new Signal(false);
		this.enrw = new Signal(false); // this.enrw.addSourceElementIO(busy);
		this.setbusy = new Signal(false); // this.setbusy.addDestinationElementIO(busy);
		this.enFFC = new Signal(false); // this.setbusy.addDestinationElementIO(busy);
										// this.setbusy.addDestinationElementIO(start);
		this.brs = new Signal(false);
		arb.brs[3] = this.brs;
		
		this.read = css.get("read");
		this.write = css.get("write");

		this.start = new FlipFlopD(komb1, new Signal(false));
		this.br = new FlipFlopRS(enFFC, brqstart, brs);
		this.busy = new FlipFlopRS(enFFC, setbusy, enrw);

		this.clkFstPhase = true;
	}

	public Signal getKomb2() {
		return komb2;
	}

	public void firsttick() throws FlipFlopException {

		start.out();
		br.out();
		busy.out();
		komb1.setActive(read.isActive() || write.isActive());
		brqstart.setActive((read.isActive() || write.isActive())
				&& !start.getOut().isActive());
	}

	public void secondtick() throws FlipFlopException {
		start.in();
		br.in();
		busy.in();
	}

	public void next() {

		if (clkFstPhase) {
			try {
				firsttick();
				/*
				 * if (enrw.isActive()) { int a = 4; }
				 */// TODO skinuti kad se proveri

			} catch (FlipFlopException e) {
				e.printStackTrace();
			}
		} else {
			try {
				komb2.setActive(br.getOut().isActive()
						&& Arbitrator.getInstance().bgs[3].isActive());
				bgr.setActive(br.getOut().isActive() && arb.bgs[3].isActive());
				setbusy.setActive(bgr.isActive() && !sysbus.getBusybus());
				secondtick();
			} catch (FlipFlopException e) {
				e.printStackTrace();
			}
		}
		komb2.setActive(br.getOut().isActive()
				&& Arbitrator.getInstance().bgs[3].isActive());
		bgr.setActive(br.getOut().isActive() && arb.bgs[3].isActive());
		setbusy.setActive(bgr.isActive() && !sysbus.getBusybus());
		clkFstPhase = !clkFstPhase;
		if (enrw.isActive())
			sysbus.setBusybus(true);
		else
			sysbus.setBusybus(false);
	}

	public void restore(String restorePoint) {
		if (singleton == null)
			singleton = new BusOvertake();
		String trim = restorePoint.replace(beginTag(), "");
		trim = trim.replace(endTag(), "");
		trim = trim.trim();
		String[] states = trim.split(" ");

		komb1.clearHistory();
		komb2.clearHistory();
		brqstart.clearHistory();
		bgr.clearHistory();
		enrw.clearHistory();
		setbusy.clearHistory();
		enFFC.clearHistory();

		komb1.setActive(Boolean.parseBoolean(states[0]));
		komb2.setActive(Boolean.parseBoolean(states[1]));
		brqstart.setActive(Boolean.parseBoolean(states[2]));
		bgr.setActive(Boolean.parseBoolean(states[3]));
		enrw.setActive(Boolean.parseBoolean(states[4]));
		setbusy.setActive(Boolean.parseBoolean(states[5]));
		enFFC.setActive(Boolean.parseBoolean(states[6]));

		start = new FlipFlopD(komb1,
				new Signal(Boolean.parseBoolean(states[7])));
		br = new FlipFlopRS(enFFC, brqstart, brs);
		busy = new FlipFlopRS(enFFC, setbusy, enrw);
		clkFstPhase = Boolean.parseBoolean(states[8]);

	}

	public String createRestorePoint() {
		String res = beginTag() + "\n\t" + komb1.isActive() + " "
				+ komb2.isActive() + " " + brqstart.isActive() + " "
				+ bgr.isActive();
		res += " " + enrw.isActive() + " " + setbusy.isActive() + " "
				+ enFFC.isActive() + " " + start.getOut().isActive() + " "
				+ clkFstPhase + "\n" + endTag();
		return res;
	}

	public String beginTag() {
		return "<BusOvertake>";
	}

	public String endTag() {
		// TODO Auto-generated method stub
		return "</BusOverTake>";
	}

	public void previousClk() {
		clkFstPhase = true;
		komb1.previousClk();
		komb2.previousClk();
		brqstart.previousClk(); // this.brqstart.addDestinationElementIO(br);
		bgr.previousClk();
		enrw.previousClk(); // this.enrw.addSourceElementIO(busy);
		setbusy.previousClk();// this.setbusy.addDestinationElementIO(busy);
		enFFC.previousClk(); // this.setbusy.addDestinationElementIO(busy);
								// this.setbusy.addDestinationElementIO(start)
		start.previousClk();
		br.previousClk();
		busy.previousClk();

	}

}
